package com.dmz.task.controller.api;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.extra.ftp.Ftp;
import com.dmz.common.utils.secure.GMUtil;
import com.dmz.task.bean.entity.TDocInfo;
import com.dmz.task.model.ApiResult;
import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.*;

/**
 * @author lee
 */
@Slf4j
@Component
public class FilePush {

    @Value("${sm4.key}")
    private String key;

    @Value("${sm4.iv}")
    private String iv;

    public ApiResult<String> push(TDocInfo doc) {

        String dfn = doc.getFileName().replace("{date}", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN))
                .replace("{yesterday}", DateUtil.format(DateUtil.yesterday(), DatePattern.PURE_DATE_PATTERN));

        doc.setFileName(dfn);

        String srcPath = doc.getSrcPath().replace("{date}", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN))
                .replace("{yesterday}", DateUtil.format(DateUtil.yesterday(), DatePattern.PURE_DATE_PATTERN));

        doc.setSrcPath(srcPath);

        String tgtPath = doc.getTgtPath().replace("{date}", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN))
                .replace("{yesterday}", DateUtil.format(DateUtil.yesterday(), DatePattern.PURE_DATE_PATTERN));

        doc.setTgtPath(tgtPath);
        List<File> files = new ArrayList<>();
        try{
            switch (doc.getSrcLoc()) {
                case 1:
                    files = getLocalFiles(doc);
                    break;
                case 2:
                case 3:
                    files = getFtpFiles(doc);
                    break;
                case 4:
                    files = getSftpFiles(doc);
                default:
                    break;
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ApiResult.fail(e.getMessage());
        }

        if (files.isEmpty()) {
            return ApiResult.fail("该目录下无文件={}", doc.getSrcPath());
        }
        StringBuilder sb = new StringBuilder();
        for (File file1 : files) {
            sb.append(file1.getName());
        }
        log.info("get file success {}====={}", doc.getDocName(), sb);

        try {
            switch (doc.getTgtLoc()) {

                case 1:
          /*      for (File f: files) {
                    FileUtil.copyFile(f.getPath(), doc.getTgtPath());
                }*/

                    break;
                case 2:
                case 3:
                    Ftp ftp = new Ftp(doc.getTgtHost(), doc.getTgtPort(), GMUtil.db(key, iv, doc.getTgtUsername()), GMUtil.db(key, iv, doc.getTgtPassword()));
                    if (ftp.getClient() == null) {
                        ftp.init();
                        log.info("ftp init success {}", doc.getTgtHost());
                    }

                    FTPClient ftpClient = ftp.getClient();
                    if (doc.getSrcLoc() == 3) {
                        //关键设置：设置为ASCII传输模式
                        ftpClient.setFileType(FTP.ASCII_FILE_TYPE);
                    } else {
                        //设置为二进制传输模式
                        ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
                    }

                    for (File f : files) {
                        ftp.upload(doc.getTgtPath(), f);
                        log.info("file {} upload ftp {}:{} success", f.getName(), doc.getTgtHost(), doc.getTgtPath());
                    }
                    ftp.close();
                    break;
                case 4:
                    JSch jsch = new JSch();

                    // 启用详细日志
                    JSch.setLogger(new Logger() {
                        @Override
                        public boolean isEnabled(int level) {
                            return true;
                        }

                        @Override
                        public void log(int level, String message) {
                            log.info("JSch DEBUG [Level {}]: {}", level, message);
                        }
                    });
                    Session session = jsch.getSession(GMUtil.db(key, iv, doc.getTgtUsername()), doc.getTgtHost(), doc.getTgtPort());
                    session.setPassword(GMUtil.db(key, iv, doc.getTgtPassword()));

                    // 配置会话属性
                    java.util.Properties config = new java.util.Properties();
                    // 首次连接时不检查主机密钥
                    config.put("StrictHostKeyChecking", "no");
                    config.put("PreferredAuthentications", "publickey,keyboard-interactive,password");
                    session.setConfig(config);
                    session.setConfig("max_packet_size", "1024000");

                    // 设置连接超时
                    session.setTimeout(10000);

                    log.info("尝试连接到 {}:{}", doc.getTgtHost(), doc.getTgtPort());
                    session.connect();

                    log.info("连接成功!");

                    // 打开SFTP通道
                    Channel channel = session.openChannel("sftp");
                    channel.connect();
                    ChannelSftp sftpChannel = (ChannelSftp) channel;

                    log.info("SFTP通道已建立");
                    //进入远程目录
                    sftpChannel.cd(doc.getTgtPath());

                    for (File f : files) {
                        //上传本地文件
                        sftpChannel.put(FileUtil.getInputStream(f), f.getName());
                        log.info("file {} upload sftp success {}:{}", f.getName(), doc.getTgtHost(), doc.getTgtPath());
                    }

                    //上传本地文件
                    //sftp.put("e:/test.jpg", "/opt/upload");
                    //关闭连接

                    // 断开连接
                    sftpChannel.disconnect();
                    session.disconnect();

                    break;
                case 5:
                    for (File f : files) {
                        FileUtil.del(f);
                        log.info("file {} del success", f.getName());
                    }
                    break;
                default:
                    break;
            }
        }catch (Exception e) {
            log.error(e.getMessage(), e);
            return ApiResult.fail(e.getMessage());
        }


        if (doc.getTgtLoc() == 2 || doc.getTgtLoc() == 3 || doc.getTgtLoc() == 4) {
            for (File file : files) {
                if ("hrxyk".equals(doc.getDocName()) && file.getName().indexOf("9693") > 0) {
                    break;
                }
                FileUtil.del(file);
                log.info("file {} delete success", file.getName());
            }
        }
        return ApiResult.success("执行成功");
    }

    private List<File> getLocalFiles(TDocInfo doc) {
        List<File> files = new ArrayList<>();
        if (Objects.equals(doc.getFileName(), "*")) {
            File[] fs = FileUtil.ls(doc.getSrcPath());
            for (File f : fs) {
                if (f.isFile()) {
                    files.add(f);
                }
            }
            return files;
        }

        String[] fileNames = doc.getFileName().split(",");
        for (String fileName : fileNames) {
            String[] se = fileName.split("\\*");
            File[] fs = FileUtil.ls(doc.getSrcPath());
            for (File f : fs) {
                if (f.isFile()) {
                    boolean flag = true;

                    for (String s : se) {
                        if (!f.getName().contains(s)) {
                            flag = false;
                            break;
                        }
                    }

                    if (flag) {
                        files.add(f);
                    }
                }
            }
        }

        return files;
    }


    private List<File> getSftpFiles(TDocInfo doc) throws Exception {
        List<File> files = new ArrayList<>();
        String[] fileNames = doc.getFileName().split(",");
        //Sftp sftp = JschUtil.createSftp(doc.getSrcHost(), doc.getSrcPort(), GMUtil.db(key, iv, doc.getSrcUsername()), GMUtil.db(key, iv, doc.getSrcPassword()));
        JSch jsch = new JSch();

        // 启用详细日志
        JSch.setLogger(new Logger() {
            @Override
            public boolean isEnabled(int level) {
                return true;
            }

            @Override
            public void log(int level, String message) {
                log.info("JSch DEBUG [Level {}]: {}", level, message);
            }
        });
        Session session = jsch.getSession(GMUtil.db(key, iv, doc.getSrcUsername()), doc.getSrcHost(), doc.getSrcPort());
        session.setPassword(GMUtil.db(key, iv, doc.getSrcPassword()));

        // 配置会话属性
        java.util.Properties config = new java.util.Properties();
        // 首次连接时不检查主机密钥
        config.put("StrictHostKeyChecking", "no");
        config.put("PreferredAuthentications", "publickey,keyboard-interactive,password");
        session.setConfig(config);
        session.setConfig("max_packet_size", "10240000");
        // 设置连接超时
        session.setTimeout(10000);

        log.info("尝试连接到 {}:{}", doc.getSrcHost(), doc.getSrcPort());
        session.connect();

        log.info("连接成功!");

        // 打开SFTP通道
        Channel channel = session.openChannel("sftp");
        channel.connect();
        ChannelSftp sftpChannel = (ChannelSftp) channel;

        log.info("SFTP通道已建立");
        //进入远程目录
        sftpChannel.cd(doc.getSrcPath());

        String tmpPath = "";
        if (doc.getTgtLoc() == 1) {
            tmpPath = doc.getTgtPath();
        }

        if (doc.getTgtLoc() == 2 || doc.getTgtLoc() == 3 || doc.getTgtLoc() == 4) {
            tmpPath = doc.getRemark();
        }

        // 列出目录内容
        Vector<?> vs = sftpChannel.ls(doc.getSrcPath());

        List<String> fs = new ArrayList<>();

        for (Object item : vs) {
            ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry) item;

            // 跳过当前目录和父目录引用
            if (".".equals(entry.getFilename()) || "..".equals(entry.getFilename())) {
                continue;
            }

            // 检查是否是文件（不是目录）
            if (!entry.getAttrs().isDir()) {
                fs.add(entry.getFilename());
            }
        }
        if ("*".equals(doc.getFileName())) {
            for (String f : fs) {
                if (".".equals(f) || "..".equals(f)) {
                    continue;
                }
                sftpChannel.cd(doc.getSrcPath());
                sftpChannel.get(f, tmpPath + File.separator + f);
                files.add(FileUtil.file(tmpPath + File.separator + f));
                log.info("file {} download success {}", f, tmpPath);
            }
        } else {
            for (String f : fs) {

                if (".".equals(f) || "..".equals(f)) {
                    continue;
                }

                for (String fileName : fileNames) {
                    String[] se = fileName.split("\\*");

                    boolean flag = true;

                    for (String s : se) {
                        if (!f.contains(s)) {
                            flag = false;
                            break;
                        }
                    }
                    if (flag) {
                        sftpChannel.cd(doc.getSrcPath());
                        sftpChannel.get(f, tmpPath + File.separator + f);
                        files.add(FileUtil.file(tmpPath + File.separator + f));
                        log.info("file {} download success {}", f, tmpPath);
                    }
                }
            }
        }
        //上传本地文件
        //sftp.put("e:/test.jpg", "/opt/upload");
        //关闭连接

        // 断开连接
        sftpChannel.disconnect();
        session.disconnect();
        return files;
    }

    private List<File> getFtpFiles(TDocInfo doc) throws Exception {
        List<File> files = new ArrayList<>();
        String[] fileNames = doc.getFileName().split(",");
        Ftp ftp = new Ftp(doc.getSrcHost(), doc.getSrcPort(), GMUtil.db(key, iv, doc.getSrcUsername()), GMUtil.db(key, iv, doc.getSrcPassword()));
        if (ftp.getClient() == null) {
            ftp.init();
            log.info("ftp init success {}", doc.getSrcHost());
        }

        FTPClient ftpClient = ftp.getClient();
        if (doc.getSrcLoc() == 3) {
            //关键设置：设置为ASCII传输模式
            ftpClient.setFileType(FTP.ASCII_FILE_TYPE);
        } else {
            //设置为二进制传输模式
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
        }

        String tmpPath = "";
        if (doc.getTgtLoc() == 1) {
            tmpPath = doc.getTgtPath();
        }

        if (doc.getTgtLoc() == 2 || doc.getTgtLoc() == 3 || doc.getTgtLoc() == 4) {
            tmpPath = doc.getRemark();
        }

        FTPFile[] fs = ftp.lsFiles(doc.getSrcPath());

        if("*".equals(doc.getFileName())) {
            for (FTPFile f : fs) {
                ftp.download(doc.getSrcPath() + File.separator + f.getName(), FileUtil.file(tmpPath));
                files.add(FileUtil.file(tmpPath + File.separator + f.getName()));
                log.info("file {} download success {}", f, tmpPath);
            }
        }else {
            for (FTPFile f : fs) {

                for (String fileName : fileNames) {
                    String[] se = fileName.split("\\*");

                    boolean flag = true;

                    for (String s : se) {
                        if (!f.getName().contains(s)) {
                            flag = false;
                            break;
                        }
                    }
                    if (flag) {
                        ftp.download(doc.getSrcPath() + File.separator + f.getName(), FileUtil.file(tmpPath));
                        files.add(FileUtil.file(tmpPath + File.separator + f.getName()));
                        log.info("file {} download success {}", f, tmpPath);
                    }
                }
            }
        }

        ftp.close();
        return files;
    }
}
